package character.inventory;

import character.point.model.CharacterPoint;

import main.gui.dataobjecteditor.BooleanEditorPanel;
import main.gui.dataobjecteditor.DataObjectEditor;
import main.gui.dataobjecteditor.DoubleEditorPanel;
import main.gui.dataobjecteditor.EnumEditorPanel;
import main.gui.dataobjecteditor.IntegerEditorPanel;
import main.gui.dataobjecteditor.StringEditorPanel;
import main.gui.workspace.WorkspaceListItem;

import data.EditorObject;
import data.ObjectDatabase;

public class InventoryStrategy extends EditorObject {

	/**
	 * Describes who can possess inventories.
	 */
	public static enum InventoryOwner {
		/* An inventory exists that all characters in the party can access. */
		PARTY,
		/* An inventory exists for each character to privately use. */
		CHARACTER
	}

	/**
	 * Describes the display orientation of spatial inventories.
	 */
	public static enum InventoryOrientation {
		/* Rows are added at the bottom to expand the inventory. */
		VERTICAL,
		/* Columns are added to the right to expand the inventory. */
		HORIZONTAL
	}

	/**
	 * Describes the type of inventory being used.
	 */
	public static enum InventoryTypeStrategy {
		/* Inventories are weight based and each item takes up a certain weight. */
		WEIGHT,
		/*
		 * Inventories are spatially based and each item takes up a certain
		 * physical area.
		 */
		SPATIAL
	}

	// Data object attributes
	private String party_inventory_name, character_inventory_name,
			character_point_name, weight_unit_name;
	private Boolean party_inventory, character_inventory;
	private InventoryTypeStrategy type;
	private InventoryOrientation orientation;
	private Integer size_of_spatial_inventory, base_size;
	private Float increase_per_point;

	/**
	 * Default constructor.
	 */
	public InventoryStrategy() {
		super();
	}

	/**
	 * Initializes all inventory strategy properties to defaults.
	 */
	@Override
	protected void initDefaultData() {
		defaults.put("party_inventory_name", "Inventory");
		defaults.put("character_inventory_name", "Inventory");
		defaults.put("party_inventory", Boolean.TRUE);
		defaults.put("character_inventory", Boolean.FALSE);
		defaults.put("type", InventoryTypeStrategy.WEIGHT);
		defaults.put("weight_unit_name", "lbs");
		defaults.put("orientation", InventoryOrientation.HORIZONTAL);
		defaults.put("size_of_spatial_inventory", 5);
		defaults.put("base_size", 50);
		defaults.put("character_point_name", "Strength");
		defaults.put("increase_per_point", 5.0d);
	}

	@Override
	public void init() {

	}

	@Override
	public DataObjectEditor buildDataObjectEditor() {
		// Setup
		String fqClassName = InventoryStrategy.class.getCanonicalName();
		DataObjectEditor editor = new DataObjectEditor(defaults.size(), 6);
		// General Inventory Header
		editor.addSectionHeader("General Options");
		// Type
		EnumEditorPanel<InventoryTypeStrategy> enumInventoryTypeEditor = new EnumEditorPanel<InventoryTypeStrategy>(
				"type", this.guid, fqClassName, InventoryTypeStrategy.values());
		editor
				.addAttributePanel(
						enumInventoryTypeEditor,
						"Inventory Type",
						"The type of inventory to use.\nWEIGHT: Inventory can hold a certain number of units of weight (ex. 250 lbs).\nSPATIAL: Inventory is made up of a grid of boxes where items are placed.",
						this.getData().get("type"));
		// Party Inventory Header
		editor.addSectionHeader("Party Inventory Options");
		// Party Inventory
		BooleanEditorPanel partyInventoryEditor = new BooleanEditorPanel(
				"party_inventory", this.guid, fqClassName);
		editor
				.addAttributePanel(
						partyInventoryEditor,
						"Party Inventory Active",
						"If this is turned on, each character in the party will be able to share one global inventory.",
						this.getData().get("party_inventory"));
		// Party Inventory Name
		StringEditorPanel partyInventoryNameEditor = new StringEditorPanel(
				"party_inventory_name", this.guid, fqClassName);
		editor.addAttributePanel(partyInventoryNameEditor,
				"Party Inventory Name",
				"The in-game name of the party inventory. (ex. \"Backpack\")",
				this.getData().get("party_inventory_name"));
		// Character Inventory Header
		editor.addSectionHeader("Character Inventory Options");
		// Character Inventory
		BooleanEditorPanel characterInventoryEditor = new BooleanEditorPanel(
				"character_inventory", this.guid, fqClassName);
		editor
				.addAttributePanel(
						characterInventoryEditor,
						"Character Inventory Active",
						"If this is turned on, each character in the party will have their own individual inventory.",
						this.getData().get("character_inventory"));
		// Character Inventory Name
		StringEditorPanel charInventoryNameEditor = new StringEditorPanel(
				"character_inventory_name", this.guid, fqClassName);
		editor
				.addAttributePanel(
						charInventoryNameEditor,
						"Character Inventory Name",
						"The in-game name of the character inventory. (ex. \"Backpack\")",
						this.getData().get("character_inventory_name"));
		// Character Inventory Header
		editor.addSectionHeader("Size Strategy Options");
		// Base Inventory Size
		IntegerEditorPanel constantSizeEditor = new IntegerEditorPanel(
				"base_size", this.guid, fqClassName, 1, 1000000);
		editor.addAttributePanel(constantSizeEditor, "Base Inventory Size",
				"", this.getData().get("base_size"));
		// Increase Per Point
		DoubleEditorPanel increasePerPointEditor = new DoubleEditorPanel(
				"increase_per_point", this.guid, fqClassName, 0.0d, 1000.0d);
		editor.addAttributePanel(increasePerPointEditor,
				"Size Increase per Character Point", "", this.getData().get(
						"increase_per_point"));
		// Weight Type Header
		editor.addSectionHeader("Weight Type Options");
		// Weight Unit Name
		StringEditorPanel weightUnitNameEditor = new StringEditorPanel(
				"weight_unit_name", this.guid, fqClassName);
		editor.addAttributePanel(weightUnitNameEditor, "Weight Unit Name", "",
				this.getData().get("weight_unit_name"));
		// Spatial Type Header
		editor.addSectionHeader("Spatial Type Options");
		// Orientation
		EnumEditorPanel<InventoryOrientation> enumOrientationEditor = new EnumEditorPanel<InventoryOrientation>(
				"orientation", this.guid, fqClassName, InventoryOrientation
						.values());
		editor.addAttributePanel(enumOrientationEditor,
				"Inventory Orientation", "", this.getData().get("orientation"));
		// Spatial Inventory Size
		IntegerEditorPanel spatialSizeEditor = new IntegerEditorPanel(
				"size_of_spatial_inventory", this.guid, fqClassName, 1, 20);
		editor.addAttributePanel(spatialSizeEditor, "Spatial Inventory Constant Width/Height",
				"", this.getData().get("size_of_spatial_inventory"));
		// Finish
		return editor;
	}

	@Override
	public boolean validateValue(String attrName, Object value) {
		if (attrName.equals("party_inventory_name")) {
			return value instanceof String;
		} else if (attrName.equals("character_inventory_name")) {
			return value instanceof String;
		} else if (attrName.equals("party_inventory")) {
			return value instanceof Boolean;
		} else if (attrName.equals("character_inventory")) {
			return value instanceof Boolean;
		} else if (attrName.equals("type")) {
			return value instanceof InventoryTypeStrategy;
		} else if (attrName.equals("weight_unit_name")) {
			return value instanceof String;
		} else if (attrName.equals("orientation")) {
			return value instanceof InventoryOrientation;
		} else if (attrName.equals("size_of_spatial_inventory")) {
			if (value instanceof Integer) {
				int temp = (Integer) value;
				return temp >= 1 && temp <= 20;
			}
			return false;
		} else if (attrName.equals("base_size")) {
			if (value instanceof Integer) {
				int temp = (Integer) value;
				return temp >= 1 && temp <= 1000000;
			}
			return false;
		} else if (attrName.equals("character_point_name")) {
			if (value instanceof String) {
				String temp = (String) value;
				return ObjectDatabase.getInstance().dataObjectExistsOfName(
						CharacterPoint.class.getCanonicalName(), temp);
			}
			return false;
		} else if (attrName.equals("increase_per_point")) {
			if (value instanceof Double) {
				double temp = (Double) value;
				return temp >= 0.0d && temp <= 1000.0d;
			}
			return false;
		}
		return false;
	}

	@Override
	public WorkspaceListItem buildWorkspaceListItem() {
		WorkspaceListItem
	}

}
